<template>
  <div class="upload-container">
    <el-upload
      ref="uploadImg"
      action="#"
      :class="[fileType === 'image'? 'image-upload':'file-upload',disabled ? 'disabled-upload': '']"
      :list-type="fileType === 'image'? 'picture-card':'text'"
      :data="extraData"
      :accept="accept"
      :limit="limit"
      :file-list="uploadList"
      :disabled="disabled"
      :http-request="uploadHandle"
      :before-upload="beforeUpload"
      :on-exceed="handleExceed"
      :on-remove="handleRemove"
      :on-preview="handlePreview"
      v-bind="$attrs"
      v-on="$listeners"
    >
      <i class="el-icon-plus file-upload-icon" :class="{ 'uploader-icon-disabled': disabled }" />
    </el-upload>
    <div class="upload-tip">
      <slot name="tip" />
    </div>
    <PreviewImg :img-url="imgUrl" :show-image.sync="showImage" />
  </div>
</template>

<script>
import { uploadFile } from '@/api/common'
import PreviewImg from '@/components/PreviewImg/index.vue'
export default {
  name: 'UploadFile',
  components: {
    PreviewImg
  },
  props: {
    // 上传文件类型
    fileType: {
      type: String,
      default: 'image' // image: 图片  file: 其他类型文件
    },
    // 上传接口其他参数
    extraData: {
      type: Object,
      default: () => ({})
    },
    // 可接受文件类型
    accept: {
      type: String,
      default: () => '.jpg,.jpeg,.png,.gif'
    },
    // 限制上传的文件数量
    limit: {
      type: Number,
      default: 1
    },
    // 已上传的文件列表
    fileList: {
      type: [Array, String],
      default: () => []
    },
    // 限制上传的文件大小 单位M 1MB = 1024KB
    size: {
      type: Number,
      default: 10
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    }
  },

  data() {
    return {
      showImage: false,
      imgUrl: ''
    }
  },

  computed: {
    uploadList() {
      // 数据回显可接受的数据形式  1. 字符串拼接 'xxx.jpg,xxx.png'  2.数组 ['xxx.jpg','xxx.png']
      if (this.fileList && typeof this.fileList === 'string') {
        console.log(1)
        const fileList = this.fileList.split(',')
        return fileList.map(item => {
          return {
            url: item,
            name: this.getFilename(item)
          }
        })
      } else if (this.fileList?.length && typeof this.fileList === 'object') {
        console.log(2)
        return this.fileList.map(item => {
          if (item.url) {
            return {
              url: item.url,
              name: item.name || this.getFilename(item)
            }
          } else {
            return {
              url: item,
              name: this.getFilename(item)
            }
          }
        })
      } else {
        console.log(3)
        return []
      }
    }
  },

  methods: {
    // 获取文件名称
    getFilename(url) {
      const index = url.lastIndexOf('/')
      if (index > -1) {
        return decodeURI(url.slice(index + 1))
      } else {
        return url
      }
    },

    // 超出文件数量限制
    handleExceed() {
      this.$message.warning(`最多只能上传${this.limit}个文件`)
    },

    // 上传前钩子
    beforeUpload(file) {
      if (file.size > 1024 * 1024 * this.size) {
        this.$message.warning(`文件【${file.name}】大小不能超过${this.size}MB`)
        return false
      }
      const fileType = file.name.substring(file.name.lastIndexOf('.')).toLowerCase()
      if (!this.accept.split(',').includes(fileType)) {
        this.$message.warning(`不支持${fileType}文件上传`)
        return false
      }
      return true
    },

    // 删除文件
    handleRemove(file, fileList) {
      this.$emit('change', { file, fileList })
    },

    // 预览文件
    handlePreview(file) {
      if (this.fileType === 'image') {
        this.imgUrl = file.url
        this.showImage = true
      } else {
        window.open(file.url)
      }
    },

    // 自定义上传文件
    uploadHandle(request) {
      const formData = new FormData()
      formData.append('file', request.file)
      Object.keys(this.extraData).map(item => {
        formData.append(item, this.extraData[item])
      })
      const { name, uid } = request.file
      uploadFile(formData).then(res => {
        const file = {
          url: res.url,
          name: name
        }
        const fileList = [
          file,
          ...this.uploadList
        ]
        this.$emit('change', { file, fileList })
      }).catch(() => {
        // 删除上传失败的文件
        const index = this.$refs.uploadImg.uploadFiles.findIndex(item => item.uid === uid)
        this.$refs.uploadImg.uploadFiles.splice(index, 1)
        this.$message.error(`文件【${name}】上传失败，请重新上传`)
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.image-upload{
  display: flex;
  align-items: flex-start;
}

.file-upload{
  display: flex;
  align-items: flex-start;
  flex-direction: column;
}

.file-upload-icon{
  display: inline-block;
  width: 100px;
  height: 100px;
  font-size: 28px;
  line-height: 100px;
  color: #8c939d;
  text-align: center;
  vertical-align: top;
}

.uploader-icon-disabled{
  cursor: not-allowed;
}

.upload-tip{
  color: #666;
  font-size: 12px;
  line-height: 30px;
}

::v-deep {
  .el-upload {
    width: 100px;
    height: 100px;
    border: 1px dashed #c0ccda;
    border-radius: 5px;
  }

  .el-upload-list__item-name{
    max-width: 400px;
  }
}

.image-upload ::v-deep .el-upload-list__item{
  width: 100px;
  height: 100px;
}

.disabled-upload ::v-deep .el-upload{
  display: none;
}

</style>
